from django import forms
from Alpha.settings import TIME_ZONE
from django_celery_beat.models import (
    DAYS, HOURS, MINUTES, SECONDS, MICROSECONDS,
    IntervalSchedule, CrontabSchedule, SolarSchedule, ClockedSchedule
)
from utils.form import BaseForm
import json


class SchedulerForm:
    class IntervalInsert(BaseForm):
        every = forms.IntegerField(min_value=1)
        period = forms.CharField()

        def clean(self):
            constraint = [DAYS, HOURS, MINUTES, SECONDS, MICROSECONDS]
            if self.cleaned_data['period'] not in constraint:
                text = 'Field "period" must be in [{}]'.format(','.join(constraint))
                raise forms.ValidationError({'period': text})

    class CrontabInsert(BaseForm):
        minute = forms.IntegerField(required=False, max_value=60, min_value=0)
        hour = forms.IntegerField(required=False, max_value=24, min_value=0)
        day_of_week = forms.IntegerField(required=False, max_value=7, min_value=1)
        day_of_month = forms.IntegerField(required=False, max_value=31, min_value=1)
        month_of_year = forms.IntegerField(required=False, max_value=12, min_value=1)

        def clean(self):
            data = self.cleaned_data
            for k, v in data.items():
                if not v:
                    data[k] = '*'
            data.setdefault('timezone', TIME_ZONE)
            return data


class TaskForm:
    class Insert(BaseForm):
        name = forms.CharField()
        task = forms.CharField()

        interval = forms.IntegerField(required=False)  # 时间表id
        crontab = forms.IntegerField(required=False)
        solar = forms.IntegerField(required=False)
        clocked = forms.IntegerField(required=False)

        kwargs = forms.CharField(required=False)

        expires = forms.DateTimeField(required=False)
        one_off = forms.BooleanField(required=False)
        description = forms.CharField()

        def _valid_scheduler(self, data):
            count_None = 0
            scheduler = [
                self.cleaned_data['interval'],
                self.cleaned_data['crontab'],
                self.cleaned_data['solar'],
                self.cleaned_data['clocked'],
            ]
            for i in scheduler:
                if not i:
                    count_None += 1
            if len(scheduler) - count_None != 1:  # scheduler中有且仅有一个字段有值
                text = 'Only one of "clocked","interval","crontab","solar" must be set'
                raise forms.ValidationError({'interval': text})
            scheduler_clean = {
                'interval': IntervalSchedule.objects.get(id=self.cleaned_data['interval']) if self.cleaned_data[
                    'interval'] else None,
                'crontab': CrontabSchedule.objects.get(id=self.cleaned_data['crontab']) if self.cleaned_data[
                    'crontab'] else None,
                'solar': SolarSchedule.objects.get(id=self.cleaned_data['solar']) if self.cleaned_data[
                    'solar'] else None,
                'clocked': ClockedSchedule.objects.get(id=self.cleaned_data['clocked']) if self.cleaned_data[
                    'clocked'] else None,
            }
            data.update(**scheduler_clean)
            return data

        def _valid_kwargs(self, data):
            if 'kwargs' in data.keys():  # 有kwargs字段
                if data['kwargs']:  # 字段不为空,判断是否为json
                    kwargs = data['kwargs']
                    try:
                        to_python = json.loads(kwargs)
                        if not isinstance(to_python, dict):
                            text = '接受对象形式的json字符串'
                            raise forms.ValidationError({'kwargs': text})
                    except TypeError and json.decoder.JSONDecodeError:  # 捕获json格式化错误
                        text = '接受json字符串'
                        raise forms.ValidationError({'kwargs': text})
                else:
                    data['kwargs'] = '{}'
            return data

        def clean(self):
            data = self.cleaned_data
            data = self._valid_scheduler(data)
            data = self._valid_kwargs(data)
            return data

    class Delete(BaseForm):
        id = forms.IntegerField()

    class Update(Insert):
        id = forms.IntegerField()

    class List(BaseForm):
        page = forms.IntegerField(min_value=1)
        page_size = forms.IntegerField(min_value=1)

        name = forms.CharField(required=False, empty_value=None)
        task = forms.CharField(required=False, empty_value=None)
        one_off = forms.NullBooleanField(required=False)
        enabled = forms.NullBooleanField(required=False)

    class ChangeStatus(BaseForm):
        id = forms.IntegerField()
        enabled = forms.NullBooleanField()


class AsyncTaskForm:
    class Result(BaseForm):
        task_id = forms.CharField()

    class ResultList(BaseForm):
        page = forms.IntegerField()
        page_size = forms.IntegerField()
